#include "stdafx.h"

#include "bochs.h"
#include "softfloatx80.h"

/* D9 C8 */
void IA32_CPU::FXCH_STi(Ia32_Instruction_c *i)
{
   prepareFPU(i);

  int st0_tag =  the_i387.FPU_gettagi(0);
  int sti_tag =  the_i387.FPU_gettagi(i->rm());

  floatx80 st0_reg = IA32_READ_FPU_REG(0);
  floatx80 sti_reg = IA32_READ_FPU_REG(i->rm());

  clear_C1();

  if (st0_tag == FPU_Tag_Empty || sti_tag == FPU_Tag_Empty)
  {
       FPU_exception(FPU_EX_Stack_Underflow);

      if( the_i387.is_IA_masked())
      {
	  /* Masked response */
          if (st0_tag == FPU_Tag_Empty)
          {
              st0_reg = floatx80_default_nan;
              st0_tag = FPU_Tag_Special;
          }
          if (sti_tag == FPU_Tag_Empty)
          {
              sti_reg = floatx80_default_nan;
              sti_tag = FPU_Tag_Special;
          }
      }
      else return;
  }

  IA32_WRITE_FPU_REGISTER_AND_TAG(st0_reg, st0_tag, i->rm());
  IA32_WRITE_FPU_REGISTER_AND_TAG(sti_reg, sti_tag, 0);
}

/* D9 E0 */
void IA32_CPU::FCHS(Ia32_Instruction_c *i)
{
   prepareFPU(i);

  int st0_tag =  the_i387.FPU_gettagi(0);
  if (st0_tag == FPU_Tag_Empty)
  {
       FPU_stack_underflow(0);
      return;
  }

  clear_C1();

  floatx80 st0_reg = IA32_READ_FPU_REG(0);
  IA32_WRITE_FPU_REGISTER_AND_TAG(floatx80_chs(st0_reg), st0_tag, 0);
}

/* D9 E1 */
void IA32_CPU::FABS(Ia32_Instruction_c *i)
{
   prepareFPU(i);

  int st0_tag =  the_i387.FPU_gettagi(0);
  if (st0_tag == FPU_Tag_Empty)
  {
       FPU_stack_underflow(0);
      return;
  }

  clear_C1();

  floatx80 st0_reg = IA32_READ_FPU_REG(0);
  IA32_WRITE_FPU_REGISTER_AND_TAG(floatx80_abs(st0_reg), st0_tag, 0);
}

/* D9 F6 */
void IA32_CPU::FDECSTP(Ia32_Instruction_c *i)
{
   prepareFPU(i);

  clear_C1();

   the_i387.tos = ( the_i387.tos-1) & 7;
}

/* D9 F7 */
void IA32_CPU::FINCSTP(Ia32_Instruction_c *i)
{
   prepareFPU(i);
  clear_C1();
   the_i387.tos = ( the_i387.tos+1) & 7;
}

/* DD C0 */
void IA32_CPU::FFREE_STi(Ia32_Instruction_c *i)
{
   prepareFPU(i);
   the_i387.FPU_settagi(FPU_Tag_Empty, i->rm());
}

/* 
 * Free the st(0) register and pop it from the FPU stack.
 * "Undocumented" by Intel & AMD but mentioned in AMDs Athlon Docs.
 */

/* DF C0 */
void IA32_CPU::FFREEP_STi(Ia32_Instruction_c *i)
{
   prepareFPU(i);
   the_i387.FPU_settagi(FPU_Tag_Empty, i->rm());
   the_i387.FPU_pop();
}
